#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<netinet/in.h>
#include <arpa/inet.h>
 
#define DEST_PORT 60000
#define DSET_IP_ADDRESS "192.168.2.100"
 
int main()
{
	int sock_fd;                        //套接字文件描述符
	int send_num;
	int recv_num;
    int i;
	socklen_t dest_len;
	char send_buf[20] = "hello yrr";
	char recv_buf[20] = {0};
	struct sockaddr_in addr_server;     //服务端地址
    fd_set sockset;                     //定义文件描述符集合
    int ret;
    // struct timeval timeout = {          //设置阻塞等待时间为3s
    //     .tv_sec = 3,
    // };
    struct timeval timeout;
	
	sock_fd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字
	//初始化服务器端地址
	memset(&addr_server,0,sizeof(addr_server));
	addr_server.sin_family = AF_INET;
	addr_server.sin_addr.s_addr = inet_addr(DSET_IP_ADDRESS);
	addr_server.sin_port = htons(DEST_PORT);
	
	dest_len = sizeof(struct sockaddr_in);
	printf("start send data 10 times:\n");
    for(i=0;i<10;i++)
    {
        send_num = sendto(sock_fd,send_buf,sizeof(send_buf),0,(struct sockaddr *)&addr_server,dest_len);
        if(send_num < 0)
        {
            perror("sendto");
            exit(1);
        } 
        else        //发出数据后等待服务端回复数据
        {
            printf("send success:%s ,waitting for server ack\n",send_buf);
            FD_ZERO(&sockset);      //初始化文件描述符集合sockset为空
            FD_SET(sock_fd,&sockset);       //添加UDP文件描述符
            timeout.tv_sec = 3;             //必须每次都要重新赋值，否则下次时间为0不等待就返回
            timeout.tv_usec = 0;            //不能少，否则一直阻塞
            ret = select(sock_fd+1,&sockset,NULL,NULL,&timeout);//阻塞直到文件描述符有数据可读才会返回，timeout设置阻塞时间
            if(ret<0)       //返回-1表示有错误发生并设置errno
            {
                perror("select err");
                exit(1);
            }
            else if(ret == 0)       //返回0表示在任何文件描述符成为就绪态之前select()调用已经超时
            {
                printf("waitting for server ack timeout\n");
            }
            else            //返回正值表示处于就绪态的文件描述符的个数，可读了
            {
                printf("ret is %d,sock_fd have data to be read:\n",ret);
                if(FD_ISSET(sock_fd,&sockset))          //判断sock_fd文件描述符是否是集合中的成员
                {
                    memset(recv_buf,0,sizeof(recv_buf));
                    recv_num = recvfrom(sock_fd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&addr_server,&dest_len);
                    if(recv_num <0)
                    {
                        perror("recvfrom");
                        exit(1);
                    } 
                    else
                    {
                        printf("recvfrom success:%s\n",recv_buf);
                    }
                }
            }
        }
    }
	close(sock_fd);
 
	return 0;
}